package service_register

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hashicorp/consul/api"
)

type ConsulServiceRegister struct {
	serviceInstances map[string]map[string]ServiceInstance
	client           *api.Client
}

func NewConsulServiceRegister(host string, port int, token string) (*ConsulServiceRegister, error) {
	if len(host) < 3 {
		return nil, errors.New("check host")
	}

	if port <= 0 || port > 65535 {
		return nil, errors.New("check port, port should between 1 and 65535")
	}

	config := api.DefaultConfig()
	config.Address = host + ":" + strconv.Itoa(port)
	config.Token = token
	client, error := api.NewClient(config)
	if error != nil {
		return nil, error
	}

	return &ConsulServiceRegister{client: client}, nil
}

func (_this *ConsulServiceRegister) Register(serviceInstance *ServiceInstance) bool {

	registration := new(api.AgentServiceRegistration)
	registration.ID = serviceInstance.InstanceId
	registration.Name = serviceInstance.ServiceId
	registration.Port = serviceInstance.Port
	var tags []string
	if serviceInstance.IsSecure {
		tags = append(tags, "secure=true")
	} else {
		tags = append(tags, "secure=false")
	}

	registration.Tags = tags
	registration.Meta = serviceInstance.Metadata

	registration.Address = serviceInstance.Host

	check := new(api.AgentServiceCheck)

	schema := "http"
	if serviceInstance.IsSecure {
		schema = "https"
	}
	check.HTTP = fmt.Sprintf("%s://%s:%d/consul/health", schema, registration.Address, registration.Port)
	check.Timeout = "1s"
	check.Interval = "3s"
	check.DeregisterCriticalServiceAfter = "10s"
	registration.Check = check

	err := _this.client.Agent().ServiceRegister(registration)
	if err != nil {
		fmt.Println(err)
		panic(err)
	}

	if _this.serviceInstances == nil {
		_this.serviceInstances = map[string]map[string]ServiceInstance{}
	}

	services := _this.serviceInstances[serviceInstance.ServiceId]

	if services == nil {
		services = map[string]ServiceInstance{}
	}

	services[serviceInstance.InstanceId] = *serviceInstance

	_this.serviceInstances[serviceInstance.ServiceId] = services

	return true
}

func (_this *ConsulServiceRegister) GetInstances(serviceId string) ([]ServiceInstance, error) {
	catalogService, _, _ := _this.client.Catalog().Service(serviceId, "", nil)
	if len(catalogService) > 0 {
		result := make([]ServiceInstance, len(catalogService))
		for index, sever := range catalogService {
			s := ServiceInstance{
				InstanceId: sever.ServiceID,
				ServiceId:  sever.ServiceName,
				Host:       sever.Address,
				Port:       sever.ServicePort,
				Metadata:   sever.ServiceMeta,
			}
			result[index] = s
		}
		return result, nil
	}
	return nil, nil
}
